import {AxiosRequestConfigs, AxiosPromise, AxiosResponse} from "@/types";
import {parseHeaders} from "@/utils/headers";
import {createError} from "@/utils/error";

enum HTTPStatusCode {
    MESSAGE=100,
    SUCCESS=200,
    REDIRECT=300,
    REQUESTERROR=400,
    SERVERERROR=500
}

export default function xhr(config: AxiosRequestConfigs): AxiosPromise {
    return new Promise((resolve, reject) => {
        const {data = null, url, method = 'get', headers, responseType, timeout} = config;
        const request = new XMLHttpRequest();
        if (responseType) {
            request.responseType = responseType;
        }
        if (timeout) {
            request.timeout = timeout;
        }

        request.open(method.toUpperCase(), url!, true);
        request.onreadystatechange = function handleLoad() {
            //改成枚举
            // 0	UNSENT	代理被创建，但尚未调用 open() 方法。
            // 1	OPENED	open() 方法已经被调用。
            // 2	HEADERS_RECEIVED	send() 方法已经被调用，并且头部和状态已经可获得。
            // 3	LOADING	下载中； responseText 属性已经包含部分数据。
            // 4	DONE
            if (request.readyState !== request.DONE) {
                return;
            }

            if (request.status === request.UNSENT) {
                return;
            }

            const responseHeaders = parseHeaders(request.getAllResponseHeaders())
            const responseData = responseType !== 'text' ? request.response : request.responseText;
            const response: AxiosResponse = {
                data: responseData,
                status: request.status,
                statusText: request.statusText,
                headers: responseHeaders,
                config,
                request,
            }
            resolve(response)
        }
        //处理网络错误
        request.onerror = function handError() {
            reject(createError('Network Error',config,null,request))
        }

        //处理超时错误
        request.ontimeout = function handleTimeOut() {
            reject(createError(`Timeout of ${timeout} ms exceeded`,config,'ECONNABORTED',request))
        }

        Object.keys(headers).forEach(name => {
            if (data === null && name.toLowerCase() === 'content-type') {
                delete headers[name];
            } else {
                request.setRequestHeader(name, headers[name]);
            }
        })
        request.send(data);
        
        function handleResponse(response:AxiosResponse) {
            if (response.status >=HTTPStatusCode.SUCCESS&&response.status<HTTPStatusCode.REDIRECT){
                resolve(response)
            }else{
                reject(createError(`Request failed with status code ${response.status}`,config,null,request,response))
            }
        }
    })
}